/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Copyright 2002-2003 by Mark Wolgemuth, All rights reserved.             */
/* Copyright 2002-2003 by Employease, Inc.  All rights reserved.           */
/*                                                                         */
/* Redistribution and use in source and binary forms, with or without      */
/* modification, are permitted provided that the following conditions      */
/* are met:                                                                */
/*                                                                         */
/*    1. Redistributions of source code must retain the above copyright    */
/* notice, this list of conditions and the following disclaimer.           */
/*    2. Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in the     */
/* documentation and/or other materials provided with the distribution.    */
/*                                                                         */
/* THIS SOFTWARE IS PROVIDED BY THE MOD_ATHENA PROJECT ``AS IS'' AND ANY   */
/* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE       */
/* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR      */
/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR        */
/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,   */
/* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,     */
/* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR      */
/* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT            */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE   */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.    */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "athd.h"

/* private data */
static int _pid = -1;
static const char *_pidfile = NULL;
static apr_pool_t *_pidfilepool = NULL;
static ath_list *_core_threads = NULL;

void 
athd_proc_exit(int status)
{
    exit(status);
}

void
athd_proc_shutdown(int sig)
{
    char *howami;
#ifdef HAVE_GETPGRP
    char *exitmsg = "Exit pgid: [%d] on user signal: [%d] (%s)";
#else
    char *exitmsg = "Exit pid: [%d] on user signal: [%d] (%s)";
#endif /* HAVE_GETPGRP */
    if (sig == SIGSEGV)
	howami = "unclean: seg fault, look for core";
    else if (sig == SIGSEGV)
	howami = "unclean: bus error, look for core";
    else if (sig == SIGINT)
	howami = "clean: tty interrupt";
    else if (sig == SIGTERM)
	howami = "clean";
    else if (sig == SIGABRT)
	howami = "unclean: aborted, assert failed";
    else
	howami = "unclean: unknown";
    if (!((sig ==  SIGINT) || (sig ==  SIGTERM)))
	DEBUGOUT("Deaddead: signal [%d] %s", sig, howami);
    athd_log(ATHD_CORE, exitmsg, GET_PID(), sig, howami);
    if (_pidfile)
	apr_file_remove(_pidfile, _pidfilepool);
}

apr_status_t
athd_proc_sig_str(const char *str)
{
    apr_status_t rv = APR_SUCCESS;
    int sig = -1;
    int pid = -1;
#ifdef HAVE_GETPGRP
    char *msg_send = "Sending signal: %d to pgid: %d\n";
#else
    char *msg_send = "Sending signal: %d to pid: %d\n";
#endif /* HAVE_GETPGRP */
    athd_conf *conf = athd_conf_current_get();
    ASSERT(conf);
    sig = ath_str_to_unix_sig(str);
    if (sig < 0)
	fprintf(stderr, "Signal not implemented: %s\n", str);
    else if (sig > 0)
      {
	  int rv_kill = 0;
	  pid = athd_proc_read_pidfile(conf);
	  if (pid < 1)
	      fprintf(stderr, "No pidfile found at [%s].\n", conf->pidfile);
	  else
	      fprintf(stdout, msg_send, sig, pid);
	  if (pid > 0)
	    {
		rv_kill = KILL_PID(pid, sig);
		if (rv_kill != 0)
		    fprintf(stderr, "Error sending signal.\n");
		else if (sig == SIGUSR2)
		    fprintf(stdout, "Daemon is running.\n");
	    }
      }
    fflush(stdout);
    fflush(stderr);
    return rv;
}

/* we keep track of pidfile to unlink it at exit */
apr_status_t
athd_proc_write_pidfile()
{
    int rv;
    apr_file_t *fh_pidfile;
    apr_pool_t *subpool;
    apr_size_t written;
    int pid;
    char *strpid;
    athd_conf *conf = athd_conf_current_get();
    ASSERT(conf);
    pid = GET_PID();

    apr_pool_create(&subpool, conf->pool);
    strpid = apr_pstrcat(subpool, (apr_ltoa(subpool, pid)), "\n", NULL);
    rv = apr_file_open(&fh_pidfile, conf->pidfile,
		       APR_WRITE|APR_CREATE, APR_OS_DEFAULT, subpool);
    if (!rv)
	rv = apr_file_write_full(fh_pidfile, strpid, strlen(strpid), &written);
    if (!rv)
	athd_log(ATHD_DEVEL, "Pid File: %s", conf->pidfile);
    else
	athd_log(ATHD_CRIT, "Cannot write pid file: %s",
		 subpool ? (athd_err_str(subpool, rv)) : "(no info)");
    if (fh_pidfile)
      {
	apr_file_close(fh_pidfile);
	/* this is so exit handler can cleanup */
	_pidfile = conf->pidfile;
	_pidfilepool = conf->pool;
      }
    if (subpool)
	apr_pool_destroy(subpool);
    return rv;
}

int
athd_proc_read_pidfile()
{
    int rv;
    apr_file_t *fh_pidfile = NULL;
    apr_pool_t *subpool;
    int pid = -1;
    athd_conf *conf = athd_conf_current_get();
    ASSERT(conf);
    apr_pool_create(&subpool, conf->pool);
    rv = apr_file_open(&fh_pidfile, conf->pidfile,
		       APR_READ, APR_OS_DEFAULT, subpool);
    if ((APR_STATUS_IS_ENOENT(rv) && (conf->passchecks)))
	fprintf(stderr, "Pidfile does not exist: %s\n", conf->pidfile);
    else if ((rv) && (conf->passchecks))
	athd_log_err(ATHD_CRIT, rv, "Error reading pid file: "); 
    else if (!rv)
      {
	  char *line;
	  /* it should NEVER be longer than 128 chars */
	  line = ath_getline(subpool, fh_pidfile, 128);
	  ath_chomp_ws(line);
	  pid = atoi(line);
	  
      }
    if (fh_pidfile)
	apr_file_close(fh_pidfile);
    if (subpool)
	apr_pool_destroy(subpool);
    return pid;
}

int
athd_proc_pid_is_alive(int pid)
{
    int rv;
    ASSERT(pid > 1);
    rv = KILL_PID(pid, SIGUSR2);
    if (rv == 0)
	return 1;
    else
	return 0;
}
